# coding=utf-8
# This is a sample Python script.
import base64
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.

import configparser
import os
import re
import subprocess
import sys
import time
from urllib.request import urlretrieve
import http.client
import json
import base64

successCount = 0
failCount = 0


class Logger(object):
    def __init__(self, file_name="Default.log", stream=sys.stdout):
        self.terminal = stream
        self.log = open(file_name, "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)

    def flush(self):
        pass


class UploadService():
    def __init__(self, conf):
        self.packageType = conf.get("artifact", "packageType")  # Maven|npm
        self.userInfo = conf.get("artifact", "userInfo")
        self.repoRelease = conf.get("artifact", "repoRelease")  # release仓库名字
        self.repoSnapshot = conf.get("artifact", "repoSnapshot")  # snapshot仓库名字
        self.logger = Logger('upload.log')
        self.suffixWhiteList = [".jar", ".pom", ".tgz"]  # 上传文件后缀名
        self.remoteRepoName = conf.get("nexus", "repoName")  # nexus仓库名称
        self.userName = conf.get("nexus", "userName")  # nexus用户名
        self.passwd = conf.get("nexus", "passwd")  # nexus密码
        self.uploadPath = conf.get("artifact", "srcDir")  # 上传文件的路径
        self.nexusAddr = conf.get("nexus", "nexusAddr")  # nexus地址
        self.nexusPort = conf.get("nexus", "nexusPort")  # nexus端口
        sys.stdout = self.logger

    def prints(self, message):
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), " ", message)

    def uploadMaven(self, filename, toUploadfile):
        global successCount
        global failCount
        self.prints("start upload file:" + filename)
        filename = filename.replace('\\', '/')
        pathList = filename.split("/")
        name = pathList[-1]
        if os.path.splitext(name)[-1] not in self.suffixWhiteList:
            self.prints("suffix not match current file no need to upload:" + filename)
            return
        version = pathList[-2]
        artifactId = pathList[-3]
        artifactName = artifactId + '-' + version
        self.prints("artifactName is : " + artifactName)
        if artifactName not in filename:
            self.prints("artifactName not right current file no need to upload:" + filename)
            return
        if version.find("-SNAPSHOT") != -1:
            repo = self.repoSnapshot
        else:
            repo = self.repoRelease
        cmd = "curl -ku \"%s\" -X PUT %s%s -T %s" % (
            self.userInfo, repo, filename, toUploadfile)
        self.prints(repo + filename)
        res = str(os.popen(cmd).readlines())
        if "\"errors\"" in res:
            failCount = failCount + 1
        else:
            successCount = successCount + 1
        self.prints(res)

    def uploadNpm(self, path, toUploadfile):
        global successCount
        global failCount
        self.prints("start upload file:%s" % (path))
        path = path.replace('\\', '/')
        pathList = path.split("/")
        name = pathList[-1]
        if os.path.splitext(name)[-1] not in self.suffixWhiteList:
            self.prints("suffix not match current file no need to upload:" + name)
            return
        newPath = ""
        pathLen = len(pathList)
        index = 0
        while (index < pathLen - 1):
            newPath = newPath + pathList[index] + "/"
            index = index + 1
        newPath = newPath + "-/"
        if "@" in pathList[0]:
            newPath = newPath + pathList[0] + "/"
        newPath = newPath + name
        repo = self.repoRelease
        cmd = "curl -ku \"%s\" -X PUT %s%s -T %s" % (
            self.userInfo, repo, newPath, toUploadfile)
        self.prints(repo + newPath)
        res = str(os.popen(cmd).readlines())
        if "\"errors\"" in res:
            failCount = failCount + 1
        else:
            successCount = successCount + 1
        self.prints(res)

    def uploadNpmV2(self, path):
        global successCount
        global failCount
        cmd = "npm publish %s --registry=%s" % (path.replace("package.json", ""), self.repoRelease)
        self.prints(cmd)
        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf-8', errors='ignore')
        stdout, stderr = process.communicate()
        res = stdout
        if "npm ERR!" in res:
            failCount = failCount + 1
        else:
            successCount = successCount + 1

    def uploadPypi(self, metadata, filename, path):
        global successCount
        global failCount

        name = metadata["name"]
        version = metadata["version"]
        uploadPath = '/' + name + '/' + version + '/' + filename
        cmd = "curl -ku \"%s\" -X PUT %s%s -T %s" % (
            self.userInfo, self.repoRelease, uploadPath, path)
        self.prints("cmd is : " + cmd)
        res = str(os.popen(cmd).readlines())

        if "\"errors\"" in res:
            failCount = failCount + 1
        else:
            successCount = successCount + 1
        self.prints(res)

    def doUpload(self, path, curFileName):
        if (os.path.isfile(path)):
            if (self.packageType == 'Maven'):
                self.uploadMaven(curFileName, path)
            if (self.packageType == 'npm' and curFileName.endswith(".tgz")):
                self.uploadNpm(curFileName, path)
            if (self.packageType == 'npm' and curFileName.endswith("package.json")):
                self.uploadNpmV2(path)
            return
        for file in os.listdir(path):
            curPath = os.path.join(path, file)
            curname = os.path.join(curFileName, file)
            self.doUpload(curPath, curname)

    def transferFile(self, packageType):
        if self.remoteRepoName is None or self.remoteRepoName == '':
            return
        nexusAddr = self.nexusAddr
        nexusPort = self.nexusPort
        repoName = self.remoteRepoName
        userName = self.userName
        passwd = self.passwd
        uploadPath = self.uploadPath
        continueFlag = True
        if not os.path.exists(uploadPath):
            os.makedirs(uploadPath)
        url = "/service/rest/v1/components?repository=" + repoName
        baseUrl=url
        tmp = userName+':'+passwd
        auth='Basic '+ base64.b64encode(tmp.encode()).decode()
        while continueFlag:
            conn = http.client.HTTPConnection(nexusAddr, nexusPort)
            conn.request("GET", url, headers={"Authorization": auth})
            response = conn.getresponse()
            data = response.read().decode()
            tmp = json.loads(data)
            items = tmp['items']
            continuationToken = tmp['continuationToken']
            if continuationToken is None:
                continueFlag = False
            if packageType == 'npm':
                self.npmDownload(items)
            if packageType == 'pypi':
                self.pypiTransFer(items)
            if packageType == 'Maven':
                self.mavenDownload(items)
            if continueFlag:
                url = baseUrl + "&continuationToken=" + continuationToken
            self.prints(url)

    def npmDownload(self, items):
        for i in items:
            group = i['group']
            name = i['name']
            path = self.uploadPath + "/"
            if group == None or len(group) == 0:
                path = path + name
            else:
                path = path + "@" + group + "/" + name
            if not os.path.exists(path):
                os.makedirs(path)
            for asset in i['assets']:
                url = asset['downloadUrl']
                pathList = url.split("/")
                filename = pathList[-1]
                self.prints(url)
                finalPath = path + "/" + filename
                try:
                    urlretrieve(url, finalPath)
                except:
                    self.prints("download error, url is "+ url)

    def pypiTransFer(self, items):
        for i in items:
            path = self.uploadPath + "/"
            name = i["name"]
            version = i["version"]
            metadata = {"name":name, "version":version}
            for asset in i['assets']:
                url = asset['downloadUrl']
                pathList = url.split("/")
                filename = pathList[-1]
                self.prints(url)
                finalPath = path + "/" + filename
                try:
                    urlretrieve(url, finalPath)
                    self.uploadPypi(metadata,filename, finalPath)
                except:
                    self.prints("trans file error, url is "+ url)
					
    def mavenDownload(self, items):
        for i in items:
            path = self.uploadPath + "/"
            group = i['group']
            name = i['name']
            version = i['version']
            path = path + group + "/" + name + "/" + version
            if not os.path.exists(path):
                os.makedirs(path)
            for asset in i['assets']:
                url = asset['downloadUrl']
                pathList = url.split("/")
                filename = pathList[-1]
                self.prints(url)
                finalPath = path + "/" + filename
                try:
                    urlretrieve(url, finalPath)
                except Exception as e:
                    self.prints("trans file error, url is "+ url)
                    self.prints("exception:%s"%e)

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    conf = configparser.RawConfigParser()
    conf.read("artifact.conf", encoding='utf-8')
    path = conf.get("artifact", "srcDir")  # 本地路径
    ups = UploadService(conf)
    repoRelease = ups.repoRelease.replace("https://", "")  # release仓库名字
    userInfoBase64 = re.sub("b\'|\\\\n|\'", "", str(base64.encodebytes(ups.userInfo.encode("utf-8"))))
    if (ups.packageType == 'npm'):
        cmd = "npm config set //%s:_auth %s" % (repoRelease, userInfoBase64)
        res = str(os.popen(cmd).readlines())
    ups.transferFile(ups.packageType)
    ups.doUpload(path, "")
    ups.prints("upload finished, successCount:%s, failCount:%s" % (successCount, failCount))
